package com.example.redis.bit.domain;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.example.redis.bit.domain.init.BitMapDataInit;
import com.example.redis.bit.enums.DataModeEnum;
import com.google.common.collect.Lists;
import org.redisson.api.RBitSet;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

@Component
public class BitMapDomain implements IActDomain{

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisConnection redisConnection;

    @Override
    public DataModeEnum getMode() {
        return DataModeEnum.BITMAP;
    }

    @Override
    public void initData() {
        new Thread(new BitMapDataInit()).start();
    }

    @Override
    public long countUsers(String date) {
        Date dateKey = DateUtil.parse(date, DatePattern.PURE_DATE_PATTERN);
        String key = DateUtil.formatDate(dateKey);
        RBitSet bitSet = redissonClient.getBitSet(key);
        return bitSet.cardinality();
    }

    @Override
    public long mem(String date) {
        Date dateKey = DateUtil.parse(date, DatePattern.PURE_DATE_PATTERN);
        String key = DateUtil.formatDate(dateKey);
        RBucket bucket = redissonClient.getBucket(key);
        return bucket.sizeInMemory();
    }

    @Override
    public boolean user(String date, Long id) {
        Date dateKey = DateUtil.parse(date, DatePattern.PURE_DATE_PATTERN);
        String key = DateUtil.formatDate(dateKey);
        RBitSet bitSet = redissonClient.getBitSet(key);
        return bitSet.get(id);
    }

    @Override
    public boolean user(String dateBegin, String dateEnd, Long id) {
        Date dateBeginObj = DateUtil.parse(dateBegin, DatePattern.PURE_DATE_PATTERN);
        Date dateEndObj = DateUtil.parse(dateEnd, DatePattern.PURE_DATE_PATTERN);

        String resultKey = "RESULT";

        List<String> luaArgs = Lists.newArrayList();
        luaArgs.add("OR");
        luaArgs.add(resultKey);

        long cnt = DateUtil.betweenDay(dateBeginObj,dateEndObj,true);
        for (int i = 0; i <= cnt ; i++) {
            Date currDate = DateUtil.offsetDay(dateBeginObj,i);
            String key = DateUtil.formatDate(currDate);
            luaArgs.add(key);
        }

        redisConnection.sync(StringCodec.INSTANCE, RedisCommands.BITOP, luaArgs.toArray(new String[]{}));

        RBitSet bitSet = redissonClient.getBitSet(resultKey);
        boolean result = bitSet.get(id);
        redissonClient.getKeys().delete(resultKey);
        return result;
    }

    @Override
    public long act(String dateBegin, String dateEnd) {
        Date dateBeginObj = DateUtil.parse(dateBegin, DatePattern.PURE_DATE_PATTERN);
        Date dateEndObj = DateUtil.parse(dateEnd, DatePattern.PURE_DATE_PATTERN);

        String resultKey = "RESULT_" + System.currentTimeMillis();

        List<String> luaArgs = Lists.newArrayList();
        luaArgs.add("OR");
        luaArgs.add(resultKey);

        long cnt = DateUtil.betweenDay(dateBeginObj,dateEndObj,true);
        for (int i = 0; i <= cnt ; i++) {
            Date currDate = DateUtil.offsetDay(dateBeginObj,i);
            String key = DateUtil.formatDate(currDate);
            luaArgs.add(key);
        }

        redisConnection.sync(StringCodec.INSTANCE, RedisCommands.BITOP, luaArgs.toArray(new String[]{}));

        RBitSet bitSet = redissonClient.getBitSet(resultKey);
        long result = bitSet.cardinality();

        redissonClient.getKeys().delete(resultKey);
        return result;
    }
}
